let xlsx = require('xlsx');
let xlsxTemplate = require('xlsx-template');
let validator = require('validator');
let fs = require('fs');
let path = require('path');
let os = require('os');
const {sep} = require('path');
const tmpDir = os.tmpdir();
let Workbook = require('xlsx-workbook').Workbook;

Date.prototype.format = function (fmt) {
    let o = {
        "M+": this.getMonth() + 1,                 //月份
        "d+": this.getDate(),                    //日
        "h+": this.getHours(),                   //小时
        "m+": this.getMinutes(),                 //分
        "s+": this.getSeconds(),                 //秒
        "q+": Math.floor((this.getMonth() + 3) / 3), //季度
        "S": this.getMilliseconds()             //毫秒
    };
    if (/(y+)/.test(fmt))
        fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
    for (let k in o)
        if (new RegExp("(" + k + ")").test(fmt))
            fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
    return fmt;
};

class excelParser {
    constructor(structure) {
        for (let key in structure) {
            let item = structure[key];
            if (item.min === undefined) structure[key].min = 0;
            if (item.type === 'enum' && item.value === undefined) {
                console.log('警告：枚举类型错误');
                structure[key].value = [];
            }
        }
        this.structure = structure;
        this.workbook = null;
    }

    _parseValue(value) {

        return {row: 0, name: 'name'};
    }

    manualExport(templateFileBinary,values) {
        return new Promise((resolve, reject) => {
            // Create a template
            let template = new xlsxTemplate(templateFileBinary);

            // Replacements take place on first sheet
            let sheetNumber = 1;

            // Set up some placeholder values matching the placeholders in the template
            // Perform substitution
            values.extractDate = new Date();
            template.substitute(sheetNumber, values);

            // Get binary data
            let d = template.generate();
            resolve(d);
        });

    }

    toExcelBinary(dataArray) {
        return new Promise((resolve, reject) => {
            let workbook = new Workbook();
            let sheet = workbook.add("导出数据");
            for (let s = 0; s < this.structure.length; s++) {
                let structure = this.structure[s];
                sheet[0][s] = structure.name;
            }
            for (let i = 0; i < dataArray.length; i++) {
                let item = dataArray[i];
                for (let s = 0; s < this.structure.length; s++) {
                    let structure = this.structure[s];
                    if (item[structure.dataName]) {
                        if (typeof item[structure.dataName] === 'object') {
                            item[structure.dataName] = JSON.stringify(item[structure.dataName]);
                        }
                        if (structure.type === 'date') {
                            sheet[i + 1][s] = new Date(item[structure.dataName]).format('yyyy-MM-dd hh:mm:ss');
                        } else {
                            sheet[i + 1][s] = item[structure.dataName];
                        }
                        sheet[i + 1][s] = item[structure.dataName];
                    }
                }
            }
            fs.mkdtemp(`${tmpDir}${sep}`, (err, folder) => {
                if (err) throw err;
                let p = path.join(folder, `${Date.now()}temp.xlsx`);
                workbook.save(p);
                let binary = fs.readFileSync(p);
                resolve(binary);
                fs.unlink(p);
            })
        });
    }


    getExampleFile() {
        // xlsx.write()
        return new Promise((resolve, reject) => {
            let workbook = new Workbook();
            let sheet = workbook.add("sheet");
            for (let i = 0; i < this.structure.length; i++) {
                let item = this.structure[i];
                sheet[0][i] = item.name;
                sheet[1][i] = item.example;
            }
            let enumList = workbook.add("填表规范");

            let c = 0;
            enumList[0][0] = '字段名';
            enumList[1][0] = '可选项';
            for (let i = 0; i < this.structure.length; i++) {
                let item = this.structure[i];
                if (item.type === 'enum') {
                    c++;
                    enumList[0][c] = item.name;
                    for (let b = 0; b < item.value.length; b++) {
                        enumList[b + 1][c] = item.value[b];
                    }

                }
            }
            fs.mkdtemp(`${tmpDir}${sep}`, (err, folder) => {
                if (err) throw err;
                // let p = path.join(__dirname, `${Date.now()}temp.xlsx`);
                let p = path.join(folder, `${Date.now()}temp.xlsx`);
                workbook.save(p);
                let binary = fs.readFileSync(p);
                resolve(binary);
                fs.unlink(p);
            })
        });
    }

    toHtml() {
        return new Promise((resolve, reject) => {
            let workbook = this.workbook;
            let sheetNames = workbook.SheetNames;
            let worksheet = workbook.Sheets[sheetNames[0]];
            resolve(xlsx.utils.sheet_to_html(worksheet));
        });
    }

    static _error(item, name) {
        return `第${item.__rowNum__ + 1}行（${JSON.stringify(item)}）缺少字段[${name}]`;
    }

    loadFile(binaryData) {
        return new Promise((resolve, reject) => {
            this.workbook = xlsx.read(binaryData);
            resolve()
        });
    }

    read() {
        //TODO this
        return new Promise((resolve, reject) => {
            let workbook = this.workbook;
            let sheetNames = workbook.SheetNames;
            let worksheet = workbook.Sheets[sheetNames[0]];
            let dataList = xlsx.utils.sheet_to_json(worksheet);
            let data = [];
            console.log('dataList :', dataList);
            for (let i = 0; i < dataList.length; i++) {
                let item = dataList[i];
                let line = {};
                for (let key in this.structure) {
                    let stItem = this.structure[key];
                    if (stItem.dataName) {
                        let value = item[stItem.name];
                        if (stItem.required && !value) {
                            reject({
                                line: item.__rowNum__ + 1,
                                data: JSON.stringify(item),
                                reason: '缺少必需字段',
                                value: stItem.name,
                            });
                            return;
                        }
                        //TODO check Data types
                        switch (stItem.type) {
                            case 'string':
                                if (!value) value = '';
                                if (!validator.isLength(value, {min: stItem.min, max: stItem.max})) {
                                    reject({
                                        line: item.__rowNum__ + 1,
                                        data: JSON.stringify(item),
                                        reason: `长度不符合要求（要求:${stItem.min}-${stItem.max}个字符）`,
                                        value: stItem.name,
                                    });
                                    return;
                                }
                                break;
                            case 'integer':
                                if (!validator.isInt(value)) {
                                    reject({
                                        line: item.__rowNum__ + 1,
                                        data: JSON.stringify(item),
                                        reason: '必须为整数类型',
                                        value: stItem.name,
                                    });
                                    reject(`第${item.__rowNum__ + 1}行（${JSON.stringify(item)}）[${stItem.name}]必须为整数类型`);
                                    return;
                                }
                                break;
                            case 'enum':
                                if (stItem.value.indexOf(value) < 0) {
                                    reject({
                                        line: item.__rowNum__ + 1,
                                        data: JSON.stringify(item),
                                        reason: `必须为以下字段的其中一种`,
                                        value: stItem.name,
                                        hint: stItem.value,
                                    });
                                    reject(`第${item.__rowNum__ + 1}行（${JSON.stringify(item)}）[${stItem.name}]必须为以下字段的其中一种：${JSON.stringify(stItem.value)}`);
                                    return;
                                }
                                break;
                            default:
                                reject(`${stItem.name}缺少类型`);
                                return;
                        }
                        line[stItem.dataName] = item[stItem.name];

                    }
                }
                data.push(line);
            }
            resolve(data)
        });
    }
}

module.exports = excelParser;